#ifndef REALCPU_H
#define REALCPU_H

// Includes
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <limits.h>
#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>

#include "../utils/mt.h"

using namespace std;

/****************** Representacion real ********************/

/******************* Declaracion de Funciones del Host *************************/
void representacionRealCPU(float *poblacionActualHost, float *nuevaPoblacionHost, float *fitnessActualHost, float *nuevoFitnessHost,int * poblacionActualAcambiar, int *  nuevaPoblacionAcambiar, float * individuosAMigrarHostCPU, MersenneTwister* mt, int iteracion, int tamVectorPoblacion, int tamVectorFitness, float *individuoAMigrarCPUaGPUhost, float* fitnessOrdenadoHostCPU, int* indicesFitnessOrdenadoHostCPU, float* probabilidadRuletaHostCPU, float* fitnessTotalParaRuletaHostCPU, unsigned long* numerosAleatoriosSeleccion, unsigned long* numerosAleatoriosCruzamiento, unsigned long* numerosAleatoriosMutacion, unsigned long* numerosAleatoriosProbabilidadCruzamiento, unsigned long* numerosAleatoriosProbabilidadMutacion, float* mejorFitnessIndividuoCPU, int tamVectorFitnessMejoresIndividuosCPU, float* mejorIndividuoCPU, int tamVectorMejoresIndividuosCPU);
void imprimirRealCPU(float* fitnessHost, float tamVectorFitness, float* poblacionHost, int tamVectorPoblacion, int iteracion);
int obtenerMejorIndividuoReal(int nroPoblacion, float* vectorFitness);

/******************* Declaracion de Funciones Global del  ********************/
 void inicializarPoblacionRealCPU(float* poblacion, float* fitnessActual, MersenneTwister *mt, int cantCromosomasPoblacion, float* fitnessOrdenadoHostCPU, float* numerosAleatoriosInicializacion);
 void mainKernelRealCPU(float* poblacionActual, float* nuevaPoblacion, float* fitnessActual, float* nuevoFitness, int * poblacionActualAcambiar, int *  nuevaPoblacionAcambiar, float* individuosAMigrar, MersenneTwister *mt, int generacionActual, int nroPoblacion, int posActual, float *individuoAMigrarCPUaGPUhost,  float* fitnessOrdenado, int* vectorIndicesFitnessOrdenado, int iteracion, float* probabilidadRuleta, float* fitnessTotalParaRuleta, unsigned long* numerosAleatoriosSeleccion, unsigned long* numerosAleatoriosCruzamiento, unsigned long* numerosAleatoriosMutacion, unsigned long* numerosAleatoriosProbabilidadCruzamiento, unsigned long* numerosAleatoriosProbabilidadMutacion, float* mejorIndividuo, float* mejorFitnessIndividuoCPU);
 void obtenerMejoresIndividuoRealCPU(float* poblacion, float* fitness, float* mejorIndividuo, float* mejorFitnessIndividuoCPU);
 void imprimirMejorIndividuoRealCPU(float* mejorFitnessIndividuoCPU, int tamVectorFitnessMejoresIndividuosCPU, float* mejorIndividuoCPU, int tamVectorMejoresIndividuosCPU, int iteracion);
 void migracionRepresentacionRealCPU(float* poblacionActual, float* fitnessActual, float* individuosAMigrar, MersenneTwister *mt, float* individuoAMigrarGPUaCPUhost);

 /******************* Declaracion de Funciones internas del  *****************/
 void individuosAMigrarRepresentacionRealCPU(float* nuevoFitness, float* nuevaPoblacion, float* individuosAMigrar, int nroPoblacion, int posActual, float *individuoAMigrarCPUaGPUhost);

 void asignarProbabilidadRuletaRealCPU(float* fitnessActual, float* probabilidadRuletaReal, float* fitnessTotalParaRuleta,  MersenneTwister *mt, int nroPoblacion, int posActual);

 int seleccionRealCPU(float* vectorFitness, MersenneTwister *mt, int ejecutarFuncion, int nroPoblacion, int posActual, float* probabilidadRuleta, int* vectorIndicesFitnessOrdenado, unsigned long* numerosAleatoriosSeleccion, int nroIndividuo);
 int seleccionPorRangoRealCPU(int* vectorIndicesFitnessOrdenado, MersenneTwister *mt, int nroPoblacion, int posActual, unsigned long* numerosAleatoriosSeleccion, int nroIndividuo);
 int seleccionPorTorneoRealCPU(float* vectorFitness, MersenneTwister *mt, int nroPoblacion, int posActual, unsigned long* numerosAleatoriosSeleccion, int nroIndividuo);
 int seleccionRuedaRuletaRealCPU(float* probabilidadRuleta, MersenneTwister *mt, int nroPoblacion, int posActual, unsigned long* numerosAleatoriosSeleccion, int nroIndividuo);

 void cruzamientoRepresentacionRealCPU(float* poblacionActual, float* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, MersenneTwister *mt, int ejecutarFuncion, int nroPoblacion, int posActual, unsigned long* numerosAleatoriosProbabilidadCruzamiento, unsigned long* numerosAleatoriosCruzamiento);
 void cruzamientoAritmeticoIndividual(float* poblacionActual, float* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual, unsigned long* numerosAleatoriosProbabilidadCruzamiento, unsigned long* numerosAleatoriosCruzamiento);
 void cruzamientoAritmeticoSimple(float* poblacionActual, float* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual, unsigned long* numerosAleatoriosProbabilidadCruzamiento, unsigned long* numerosAleatoriosCruzamiento);
 void cruzamientoAritmeticoCompleto(float* poblacionActual, float* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual, unsigned long* numerosAleatoriosProbabilidadCruzamiento, unsigned long* numerosAleatoriosCruzamiento);

 void mutacionRealCPU(float* poblacion, float probabilidad, MersenneTwister *mt, int ejecutarFuncion, int generacionActual, int nroPoblacion, int posActual, unsigned long* numerosAleatoriosProbabilidadMutacion, unsigned long* numerosAleatoriosMutacion);
 void mutacionUniforme(float* poblacion, float probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual, unsigned long* numerosAleatoriosProbabilidadMutacion, unsigned long* numerosAleatoriosMutacion);
 void mutacionNoUniforme(float* poblacion, float probabilidad, MersenneTwister *mt, int generacionActual, int nroPoblacion, int posActual, unsigned long* numerosAleatoriosProbabilidadMutacion, unsigned long* numerosAleatoriosMutacion);

 void asignarFitnessRealCPU(float* poblacion, float* vectorFitness, int nroPoblacion, int posActual, float* fitnessOrdenado);

 void reemplazoRealCPU(float * poblacionActual, float * nuevaPoblacion, int * poblacionActualAcambiar, int * nuevaPoblacionAcambiar, float * fitnessActual, float* nuevoFitness, int ejecutarFuncion, int nroPoblacion, int posActual);
 void reemplazoElitistaRealCPU(float* poblacionActual, float* nuevaPoblacion, int* poblacionActualAcambiar, int* nuevaPoblacionAcambiar, float * fitnessActual, float* nuevoFitness, int nroPoblacion, int posActual);

#endif
